﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace ControleRepresentante.Logic.Models
{
    public class IndexColumnsPreference : ModelBase
    {
        private readonly IList<BuiltInIndexColumnPreference> m_BuiltInIndexColumnPreferences;
        private readonly IList<AttributeIndexColumnPreference> m_AttributeIndexColumnPreferences;

        public IndexColumnsPreference()
        {
            m_BuiltInIndexColumnPreferences = new List<BuiltInIndexColumnPreference>();
            m_AttributeIndexColumnPreferences = new List<AttributeIndexColumnPreference>();
        }

        public virtual Area Area { get; set; }
        public virtual User User { get; set; }
        public virtual IEnumerable<BuiltInIndexColumnPreference> BuiltInIndexColumnPreferences { get { return m_BuiltInIndexColumnPreferences; } }
        public virtual IEnumerable<AttributeIndexColumnPreference> AttributeIndexColumnPreferences { get { return m_AttributeIndexColumnPreferences; } }

        private void AddBuiltInIndexColumnPreference(Guid columnId)
        {
            if (!m_BuiltInIndexColumnPreferences.Any(x => x.ColumnId == columnId))
            {
                m_BuiltInIndexColumnPreferences.Add(new BuiltInIndexColumnPreference
                {
                    ColumnId = columnId,
                    IndexColumnsPreference = this
                });
            }
        }

        private void RemoveBuiltInIndexColumnPreference(Guid columnId)
        {
            BuiltInIndexColumnPreference builtInIndexColumnPreference = m_BuiltInIndexColumnPreferences.FirstOrDefault(x => x.ColumnId == columnId);
            if (builtInIndexColumnPreference != null)
            {
                m_BuiltInIndexColumnPreferences.Remove(builtInIndexColumnPreference);
            }
        }

        private void AddAttributeIndexColumnPreference(Attribute attribute)
        {
            if (!m_AttributeIndexColumnPreferences.Any(x => x.Attribute.Id == attribute.Id))
            {
                AttributeIndexColumnPreference attributeIndexColumnPreference = new AttributeIndexColumnPreference
                {
                    Attribute = attribute,
                    IndexColumnsPreference = this
                };
                m_AttributeIndexColumnPreferences.Add(attributeIndexColumnPreference);
                attribute.AddAttributeIndexColumnPreferences(attributeIndexColumnPreference);
            }
        }

        private void RemoveAttributeIndexColumnPreference(Attribute attribute)
        {
            AttributeIndexColumnPreference attributeIndexColumnPreference = m_AttributeIndexColumnPreferences.FirstOrDefault(x => x.Attribute.Id == attribute.Id);
            if (attributeIndexColumnPreference != null)
            {
                m_AttributeIndexColumnPreferences.Remove(attributeIndexColumnPreference);
                attribute.RemoveAttributeIndexColumnPreferences(attributeIndexColumnPreference);
            }
        }

        public virtual void SetBuiltInIndexColumnPreferences(IEnumerable<Guid> builtInIndexColumns)
        {
            Guid[] toAdd = builtInIndexColumns.Except(m_BuiltInIndexColumnPreferences.Select(x => x.ColumnId)).ToArray();
            Guid[] toRemove = m_BuiltInIndexColumnPreferences.Select(x => x.ColumnId).Except(builtInIndexColumns).ToArray();

            foreach (Guid id in toAdd)
            {
                AddBuiltInIndexColumnPreference(id);
            }

            foreach (Guid id in toRemove)
            {
                RemoveBuiltInIndexColumnPreference(id);
            }
        }

        public virtual void SetAttributeIndexColumnPreferences(IEnumerable<Attribute> attributeIndexColumns)
        {
            AttributeEqualityComparer attributeEqualityComparer = new AttributeEqualityComparer();
            Attribute[] toAdd = attributeIndexColumns.Except(m_AttributeIndexColumnPreferences.Select(x => x.Attribute), attributeEqualityComparer).ToArray();
            Attribute[] toRemove = m_AttributeIndexColumnPreferences.Select(x => x.Attribute).Except(attributeIndexColumns, attributeEqualityComparer).ToArray();

            foreach (Attribute attribute in toAdd)
            {
                AddAttributeIndexColumnPreference(attribute);
            }

            foreach (Attribute attribute in toRemove)
            {
                RemoveAttributeIndexColumnPreference(attribute);
            }
        }

        private class AttributeEqualityComparer : IEqualityComparer<Attribute>
        {
            public bool Equals(Attribute x, Attribute y)
            {
                if (x == null && y == null) return true;
                if (x == null) return y.Equals(x);
                return x.Equals(y);
            }

            public int GetHashCode(Attribute obj)
            {
                return obj == null ? 0 : obj.GetHashCode();
            }
        }
    }

    public class BuiltInIndexColumnPreference : ModelBase
    {
        public virtual IndexColumnsPreference IndexColumnsPreference { get; set; }
        public virtual Guid ColumnId { get; set; }
    }

    public class AttributeIndexColumnPreference : ModelBase
    {
        public virtual IndexColumnsPreference IndexColumnsPreference { get; set; }
        public virtual Attribute Attribute { get; set; }
    }
}